package de.peacei.android.ioex_notesapp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

/**
 * @author Matthias
 * 
 */
public class IOEx_NotesAppActivity extends Activity {

    private final int REFRESH_ID = 1;
    private final int ADD_ID = 2;

    private final String BACKEND_URL = "https://ioextended12nordderby.appspot.com";

    private ListView notesListView;
    private NoteListAdapter notesAdapter;
    
    private DefaultHttpClient httpClient = new DefaultHttpClient();;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

        setContentView(R.layout.main);
        setProgressBarIndeterminateVisibility(false);
        notesListView = (ListView) findViewById(R.id.listview_notes);
        notesListView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> arg0, View currentView, int position, long id) {
                Intent intent = new Intent(IOEx_NotesAppActivity.this, NoteActivity.class);
                intent.putExtra(NoteActivity.EXTRA_NOTE, notesAdapter.getItem(position).getText());
                startActivity(intent);    
            }
            
        });
        
        notesAdapter = new NoteListAdapter(this);
        notesListView.setAdapter(notesAdapter);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(Menu.NONE, REFRESH_ID, MenuItem.SHOW_AS_ACTION_ALWAYS, "Refresh");
        menu.add(Menu.NONE, ADD_ID, MenuItem.SHOW_AS_ACTION_ALWAYS, "Add note");
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case REFRESH_ID:
            AuthenticatedNotesTask fetchTask = new AuthenticatedNotesTask();
            fetchTask.execute();
            return true;
        case ADD_ID:
            Intent intent = new Intent(this, NoteActivity.class);
            startActivityForResult(intent, 1);
            
            AuthenticatedNotesTask addTask = new AuthenticatedNotesTask();
            addTask.execute("Hallo, ich bin eine Notiz.");
            return true;
        default:
            return false;
        }
    }
    
    @Override
    protected void onActivityResult(final int requestCode,
            final int resultCode, final Intent data) {
        if(resultCode == RESULT_OK) {
            String note = data.getExtras().getString(NoteActivity.EXTRA_NOTE);
            AuthenticatedNotesTask addTask = new AuthenticatedNotesTask();
            addTask.execute(note);
        }
        
    }

    @Override
    protected void onResume() {
        super.onResume();
        Intent intent = getIntent();
        AccountManager accountManager = AccountManager.get(getApplicationContext());
        Account account = (Account) intent.getExtras().get("account");
        accountManager.getAuthToken(account, "ah", false, new GetAuthTokenCallback(), null);
    }

    private void updateUI(List<Note> noteList) {
        List<Note> list = new ArrayList<Note>(noteList);
        
        notesListView.setAdapter(notesAdapter);
    }

    private List<Note> resultToNotesList(String result) {
        List<Note> notesList = new ArrayList<Note>();

        JSONArray jsonNotesArray;
        try {
            jsonNotesArray = new JSONArray(result);

            for (int i = 0; i < jsonNotesArray.length(); i++) {
                JSONObject jsonNote = jsonNotesArray.getJSONObject(i);
                Note note = new Note(jsonNote.getString("user"), jsonNote.getString("content"));
                notesList.add(note);
            }
        } catch (JSONException e) {
           return null; 
        }

        return notesList;
    }

    private String inputStreamToString(final InputStream is) throws IOException {
        String line = "";
        StringBuilder total = new StringBuilder();

        // Wrap a BufferedReader around the InputStream
        BufferedReader rd = new BufferedReader(new InputStreamReader(is));

        // Read response until the end
        while ((line = rd.readLine()) != null) {
            total.append(line);
        }

        // Return full string
        return total.toString();
    }

    private class GetAuthTokenCallback implements AccountManagerCallback {
        public void run(AccountManagerFuture result) {
            Bundle bundle;
            try {
                bundle = (Bundle) result.getResult();
                Intent intent = (Intent) bundle.get(AccountManager.KEY_INTENT);
                if (intent != null) {
                    // User input required
                    startActivity(intent);
                } else {
                    onGetAuthToken(bundle);
                }
            } catch (OperationCanceledException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (AuthenticatorException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        protected void onGetAuthToken(Bundle bundle) {
            String auth_token = bundle.getString(AccountManager.KEY_AUTHTOKEN);
            new GetCookieTask().execute(auth_token);
        }
    };

    private class GetCookieTask extends AsyncTask<String, Void, Boolean> {

        protected Boolean doInBackground(String... tokens) {
            try {
                // Don't follow redirects
                httpClient.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);

                HttpGet http_get = new HttpGet(BACKEND_URL + "/_ah/login?continue=http://localhost/&auth=" + tokens[0]);
                HttpResponse response;
                response = httpClient.execute(http_get);
                if (response.getStatusLine().getStatusCode() != 302)
                    // Response should be a redirect
                    return false;

                for (Cookie cookie : httpClient.getCookieStore().getCookies()) {
                    if (cookie.getName().equals("SACSID"))
                        return true;
                }
            } catch (ClientProtocolException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                httpClient.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, true);
            }
            return false;
        }

        protected void onPostExecute(Boolean result) {
            if (result)
                new AuthenticatedNotesTask().execute();
        }
    }

    private class AuthenticatedNotesTask extends AsyncTask<String, Void, List<Note>> {

        @Override
        protected void onPreExecute() {
            IOEx_NotesAppActivity.this.setProgressBarIndeterminateVisibility(true);
        }

        @Override
        protected List<Note> doInBackground(String... notes) {

            try {

                if (notes.length > 0) {
                    HttpPost httpPost = new HttpPost(BACKEND_URL + "/notes/new");

                    // HttpParams httpBodyParams = httpClient.getParams();
                    // httpBodyParams.setParameter("note", notes[0]);

                    List<NameValuePair> postParams = new ArrayList<NameValuePair>(1);
                    postParams.add(new PostParam("note", notes[0]));

                    httpPost.setEntity(new UrlEncodedFormEntity(postParams));

                    httpClient.execute(httpPost);
                    return null;

                } else {

                    HttpGet httpGet = new HttpGet(BACKEND_URL + "/notes");
                    HttpResponse response = httpClient.execute(httpGet);

                    return resultToNotesList(inputStreamToString(response.getEntity().getContent()));
                }

            } catch (MalformedURLException e) {
                e.printStackTrace();
                return null;
            } catch (IOException ioEx) {
                ioEx.printStackTrace();
                return null;
            }

            // List<Note> list = new ArrayList<Note>();
            // list.add(new Note("Note 1", "BLA BLUB"));
            // list.add(new Note("Note 2", "BLUB BLA"));
            // list.add(new Note("Note 3", "MOEP"));

            // return list;
        }

        @Override
        protected void onPostExecute(List<Note> notes) {

            IOEx_NotesAppActivity.this.setProgressBarIndeterminateVisibility(false);
            if (notes != null) notesAdapter.setNotes(notes);
                
        }
    }

    private class PostParam implements NameValuePair {

        private String name;
        private String value;

        public PostParam(String name, String value) {
            this.name = name;
            this.value = value;
        }

        @Override
        public String getName() {
            return this.name;
        }

        @Override
        public String getValue() {
            return this.value;
        }
    }

}